/*
Debugging code from Bruce Dawson

Summary of contents:
	- assert()  -- Only active in debug builds.
	- passert() -- Active in both debug and profile builds.
	- rassert() -- Active in debug, profile, and release builds.
	- verify()  -- Only raises an assert in debug builds, but the sent
					expression is *evaluated* in all builds.
	- dprintf() -- Accepts printf-style arguments. Prints to the debug
					output window in debug and profile builds.

	Assert handler code has been supplied by Bruce Dawson.  Improvements include
	  recursion checks, the ability to break to the line of execution (instead of
	  assert.c), and a stronger output window that makes the filename visible.
*/

#ifndef DEBUGGING_H
	#define DEBUGGING_H
#endif

#ifdef	_MSC_VER	// True when compiling with VC++
	// A handy macro for breaking into the debugger on the current line
	// of code.
	#define	DEBUG_BREAK() __asm { int 3 }
#else
	#define	DEBUG_BREAK() DebugBreak()
#endif

// Asserts are good. However Microsoft's implementation is not always good.
// It can very easily cause infinitely recursive asserts, because when the
// assert dialog appears it runs a message pump, which can cause messages
// to be delivered to your window - which can cause your assert to trigger
// again.
// Recursion: n. see recursion.
// Also, if you click 'Debug' on one of Microsoft's assert you get dropped
// into the assert.c source file, instead of into your own source code.
// This assert macro fixes these problems.


// Make sure we've wiped out any previous definitions.
#undef assert__
#undef assert
#undef passert
#undef rassert
#undef verify
#undef dprintf

bool __cdecl _csassert(const char* expr, const char* filename, unsigned int lineno);

// In debug mode we need an assert macro and an assert function.
// _csassert() returns true if the user requests debugging.


// hide constant expression and void* conversion warnings
#define assert__(exp) \
			{ \
				bool failed = (exp) ? false : true; \
				if (failed) { \
					dprintf("%s(%d): Assertion failed\n%s\n", __FILE__, __LINE__, #exp); \
					if (_csassert(#exp, __FILE__, __LINE__)) \
						DEBUG_BREAK(); \
					} \
			}

typedef bool (__cdecl * AssertFunction)(const char* expr, const char* filename, unsigned int lineno);
void __cdecl SetAssertOverrideFunction(AssertFunction assertFunction);

#if	defined(_DEBUG)
	// Use the normal assert macro in debug builds.
	#define assert(exp)   assert__(exp)
	#define passert(exp)  assert__(exp)
	#define rassert(exp)  assert__(exp)
	#define	verify(exp)	  assert__(exp)

#elif defined(_PROFILE)
	// Use the passert macro in profile builds.
	#define assert(exp)   ((void)0)
	#define passert(exp)  assert__(exp)
	#define rassert(exp)  assert__(exp)
	#define	verify(exp)	  exp

#elif defined (_RELEASE)
	// Use the rassert macro in release builds.
	#define assert(exp)   ((void)0)
	#define passert(exp)  ((void)0)
	#define rassert(exp)  assert__(exp)
	#define	verify(exp)	  exp

// rassert is an assert macro that stays in in release builds.
// It doesn't do much - just crash, or break into the debugger.
// However that is frequently much better than continuing on
// in a bad state.
// Also, with a .pdb file that's all you need to trace where
// the problem occurred. Use these for important checks where
// the modest overhead won't be too great. If an exception
// handler is initialized then a full error log will be recorded
// if a release assert is triggered outside of the debugger.

#else // no defined type, assume profile -- why? I don't know why.
	#define assert(exp)   ((void)0)
	#define passert(exp)  assert__(exp)
	#define rassert(exp)  assert__(exp)
	#define	verify(exp)	  exp
#endif

// rdprintf is always compiled in. dprintf only exists in debug and profile builds.
// rdprintf and dprintf are for printing to the debugger with
// OutputDebugString, however they allow formatted printing like
// dprintf.
void __cdecl rdprintf( const char *buf, ... );

#if	defined(_DEBUG) || defined(_PROFILE) || defined(ALLOWDPRINTF)
	// In debug builds dprintf is the same as rdprintf.
	#define	dprintf	rdprintf
#else
	// Wacky macro to completely remove dprintf from release mode
	// programs. Don't try this at home...
	#define	dprintf	0 &&
#endif

//#endif // DEBUGGING_H